#pragma once

#include "sum.h"
#include "crc.h"
#include "hex.h"
#include "b64.h"
#include "md5.h"
#include "sha.h"
#include "aes.h"
#include "rsa.h"


OPEN_JLIB_NS


struct Cipher {


  constexpr static uwl hexEncodeSize (uwl src_size) noexcept {
    return hex::encode_size(src_size);
  }

  constexpr static uwl hexDecodeSize (uwl src_size) noexcept {
    return hex::decode_size(src_size);
  }

  inline static uwl hex_encode (void *dst, const void *src, uwl src_size, bool lower_case = false) noexcept {
    return hex::encode(dst, src, src_size, lower_case);
  }

  inline static swl hex_decode (void *dst, const void *src, uwl src_size) noexcept {
    return hex::decode(dst, src, src_size);
  }

  inline static uwl hex_decode_unsafe (void *dst, const void *src, uwl src_size) noexcept {
    return hex::decode_unsafe(dst, src, src_size);
  }


  constexpr static unsigned long b64_encode_size (unsigned long src_size) noexcept {
    return b64::encode_size(src_size);
  }

  constexpr static unsigned long b64_decode_size (unsigned long src_size) noexcept {
    return b64::decode_size(src_size);
  }

  inline static unsigned long b64_encode (void *dst, const void *src, unsigned long src_size) noexcept {
    return b64::encode(dst, src, src_size);
  }

  inline static long b64_decode (void *dst, const void *src, unsigned long src_size) noexcept {
    return b64::decode(dst, src, src_size);
  }

  inline static unsigned long b64_decode_unsafe (void *dst, const void *src, unsigned long src_size) noexcept {
    return b64::decode_unsafe(dst, src, src_size);
  }


  inline constexpr static unsigned long md5_hash_size () noexcept {
    return md5::hash_size();
  }

  inline static unsigned long md5_hash (void *dst, const void *src, unsigned long src_size) noexcept {
    return md5::hash(dst, src, src_size);
  }


  inline constexpr static unsigned long sha_hash_size (int version) noexcept {
    return sha::hash_size(version);
  }

  inline static long sha_hash (void *dst, const void *src, unsigned long src_size, int version = 1) noexcept {
    return sha::hash(dst, src, src_size, version);
  }


  inline constexpr static unsigned long aes_encrypt_size (unsigned long src_size) noexcept {
    return aes::encrypt_size(src_size);
  }

  inline constexpr static unsigned long aes_decrypt_size (unsigned long src_size) noexcept {
    return aes::decrypt_size(src_size);
  }

  inline bool aes_setup (const void *key, unsigned long bits) noexcept {
    return this->_aes.setup(key, bits);
  }

  inline void aes_reset () noexcept {
    this->_aes.reset();
  }

  inline unsigned long
  aes_encrypt (void *dst, const void *src, unsigned long src_size, unsigned char ivec[16]) noexcept {
    return this->_aes.encrypt(dst, src, src_size, ivec);
  }

  inline unsigned long
  aes_decrypt (void *dst, const void *src, unsigned long src_size, unsigned char ivec[16]) noexcept {
    return this->_aes.decrypt(dst, src, src_size, ivec);
  }


  inline unsigned long rsa_private_encrypt_size (unsigned long src_size) noexcept {
    return this->_rsa.private_encrypt_size(src_size);
  }

  inline unsigned long rsa_private_decrypt_size (unsigned long src_size) noexcept {
    return this->_rsa.private_decrypt_size(src_size);
  }

  inline unsigned long rsa_public_encrypt_size (unsigned long src_size) noexcept {
    return this->_rsa.public_encrypt_size(src_size);
  }

  inline unsigned long rsa_public_decrypt_size (unsigned long src_size) noexcept {
    return this->_rsa.public_decrypt_size(src_size);
  }

  inline bool rsa_setup_private (const char *filename) noexcept {
    return this->_rsa.setup_private(filename);
  }

  inline bool rsa_setup_private (const void *key, unsigned long size) noexcept {
    return this->_rsa.setup_private(key, size);
  }

  inline bool rsa_setup_public (const char *filename) noexcept {
    return this->_rsa.setup_public(filename);
  }

  inline bool rsa_setup_public (const void *key, unsigned long size) noexcept {
    return this->_rsa.setup_public(key, size);
  }

  inline void rsa_reset_private () noexcept {
    this->_rsa.reset_private();
  }

  inline void rsa_reset_public () noexcept {
    this->_rsa.reset_public();
  }

  inline long rsa_private_encrypt (void *dst, const void *src, unsigned long src_size) noexcept {
    return this->_rsa.private_encrypt(dst, src, src_size);
  }

  inline long rsa_private_decrypt (void *dst, const void *src, unsigned long src_size) noexcept {
    return this->_rsa.private_decrypt(dst, src, src_size);
  }

  inline long rsa_public_encrypt (void *dst, const void *src, unsigned long src_size) noexcept {
    return this->_rsa.public_encrypt(dst, src, src_size);
  }

  inline long rsa_public_decrypt (void *dst, const void *src, unsigned long src_size) noexcept {
    return this->_rsa.public_decrypt(dst, src, src_size);
  }


  unsigned long signature_size () noexcept;

  long signature (void *dst, const void *src, unsigned long src_size) noexcept;

  bool verify (const void *src, unsigned long src_size, const void *signature, unsigned long sign_size) noexcept;


private:
  sha _sha;
  aes _aes;
  rsa _rsa;
};


}
CLOSE_JLIB_NS